/**
 * @file spi_config.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2022-03-09
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#include "spi_config.h"
#include "bsp.h"

// 关节以及推杆绝对式编码器SPI接口的针脚、时钟配置
#define ENC_SCK_Pin         GPIO_PIN_13
#define ENC_SCK_GPIO_Port   GPIOB
#define ENC_SCK_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()

#define ENC_MISO_Pin        GPIO_PIN_14
#define ENC_MISO_GPIO_Port  GPIOB
#define ENC_MISO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()

#define ENC_MOSI_Pin        GPIO_PIN_15
#define ENC_MOSI_GPIO_Port  GPIOB
#define ENC_MOSI_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()

#define ENC_SPI_PIN_AF      GPIO_AF5_SPI2

// #define ENC_SPI_FORCE_RESET()       __HAL_RCC_SPI1_FORCE_RESET()
// #define ENC_SPI_RELEASE_RESET()     __HAL_RCC_SPI1_RELEASE_RESET()
#define ENC_SPI_CLK_ENABLE()        __HAL_RCC_SPI2_CLK_ENABLE()

// 外部存储SPI接口的针脚、时钟配置
#define STORAGE_SCK_Pin          GPIO_PIN_5
#define STORAGE_SCK_GPIO_Port    GPIOA
#define STORAGE_SCK_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()

#define STORAGE_MISO_Pin         GPIO_PIN_6
#define STORAGE_MISO_GPIO_Port   GPIOA
#define STORAGE_MISO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()

#define STORAGE_MOSI_Pin         GPIO_PIN_7
#define STORAGE_MOSI_GPIO_Port   GPIOA
#define STORAGE_MOSI_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()

#define STORAGE_SPI_PIN_AF           GPIO_AF5_SPI1

// #define PR_SPI_FORCE_RESET()        __HAL_RCC_SPI2_FORCE_RESET()
// #define PR_SPI_RELEASE_RESET()      __HAL_RCC_SPI2_RELEASE_RESET()
#define STORAGE_SPI_CLK_ENABLE()         __HAL_RCC_SPI1_CLK_ENABLE()


// 关节、腿长调节推杆绝对式编码器SPI中断
#define ENC_SPI_IRQ_PRIO     8
#define ENC_SPI_IRQn        SPI2_IRQn
#define ENC_SPI_IRQHandler  SPI2_IRQHandler

// 外部存储SPI中断
#define STORAGE_SPI_IRQ_PRIO      9
#define STORAGE_SPI_IRQn         SPI1_IRQn
#define STORAGE_SPI_IRQHandler   SPI1_IRQHandler

// #define SPIx_TX_DMA_CHANNEL DMA_CHANNEL_3
// #define SPIx_TX_DMA_STREAM DMA2_Stream3
// #define SPIx_RX_DMA_CHANNEL DMA_CHANNEL_3
// #define SPIx_RX_DMA_STREAM DMA2_Stream0

// #define SPIx_DMA_TX_IRQn DMA2_Stream3_IRQn
// #define SPIx_DMA_RX_IRQn DMA2_Stream0_IRQn
// #define SPIx_DMA_TX_IRQHandler DMA2_Stream3_IRQHandler
// #define SPIx_DMA_RX_IRQHandler DMA2_Stream0_IRQHandler

// TDK绝对式编码器SPI接口(IFx针脚)考虑外部电路阻容滤波后（参考电路）最大速率为300kHz，详见《TAD2141_Angle_sensor_specification_Rev3v13.pdf》page18
// 《TAD2141_Angle_sensor_specification_Rev3v13.pdf》page29，原生SCLK speed可达到10Mbit/s
// 实际使用的阻容滤波电路经测试32分频也可正常使用，保险起见,因此配置SPI1速率为64分频，84MHz/64 =  1.3125MHz
// SPI硬件配置
SPI_HandleTypeDef hspix[SPI_TOTAL_NUM] = 
{
    [STORAGE_SPI_INDEX] = 
    {
        .Instance = STORAGE_SPI,
        .Init.Mode = SPI_MODE_MASTER,
        .Init.Direction = SPI_DIRECTION_2LINES,
        .Init.DataSize = SPI_DATASIZE_8BIT,
        .Init.CLKPolarity = SPI_POLARITY_LOW,
        .Init.CLKPhase = SPI_PHASE_2EDGE,
        .Init.NSS = SPI_NSS_SOFT,
        .Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32,
        .Init.FirstBit = SPI_FIRSTBIT_MSB,
        .Init.TIMode = SPI_TIMODE_DISABLE,
        .Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
        .Init.CRCPolynomial = 10,
    },

    [ENC_SPI_INDEX] = 
    {
        .Instance = ENC_SPI,
        .Init.Mode = SPI_MODE_MASTER,
        .Init.Direction = SPI_DIRECTION_2LINES,
        .Init.DataSize = SPI_DATASIZE_8BIT,
        .Init.CLKPolarity = SPI_POLARITY_LOW,
        .Init.CLKPhase = SPI_PHASE_2EDGE,
        .Init.NSS = SPI_NSS_SOFT,
        .Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64,
        .Init.FirstBit = SPI_FIRSTBIT_MSB,
        .Init.TIMode = SPI_TIMODE_DISABLE,
        .Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
        .Init.CRCPolynomial = 10,
    },
};

static void configSPI_IT_DMA_NVIC(SPI_HandleTypeDef *spiHandle);

/**
 * @brief 初始化SPI
 * 
 * @param spi_No SPI序号
 */
void spixInit(void)
{
    for (uint8_t i = 0; i < SPI_TOTAL_NUM; i++)
    {
        /* 复位SPI */
        if (HAL_SPI_DeInit(&hspix[i]) != HAL_OK)
        {
            Error_Handler(__FILE__, __LINE__);
        }

        /* 初始化SPI */
        if (HAL_SPI_Init(&hspix[i]) != HAL_OK)
        {
            Error_Handler(__FILE__, __LINE__);
        }
    }
}

/**
 * @brief 配置SPI总线时钟，GPIO，中断，DMA等，
 * 由spixInit()函数中的HAL_SPI_Init()函数调用
 * 
 * @param _hspi SPI_HandleTypeDef 类型指针变量
 */
void HAL_SPI_MspInit(SPI_HandleTypeDef *spiHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    /* 配置 SPI总线GPIO : SCK MOSI MISO */
    if (ENC_SPI == spiHandle->Instance)
    {
        /* SPI和GPIO时钟 */
        ENC_SPI_CLK_ENABLE();   //SPI时钟
        ENC_SCK_CLK_ENABLE();
        ENC_MISO_CLK_ENABLE();
        ENC_MOSI_CLK_ENABLE();

        /* SPI SCK */
        GPIO_InitStruct.Pin = ENC_SCK_Pin;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = ENC_SPI_PIN_AF;
        HAL_GPIO_Init(ENC_SCK_GPIO_Port, &GPIO_InitStruct);

        /* SPI MISO */
        GPIO_InitStruct.Pin = ENC_MISO_Pin;
        HAL_GPIO_Init(ENC_MISO_GPIO_Port, &GPIO_InitStruct);

        /* SPI MOSI */
        GPIO_InitStruct.Pin = ENC_MOSI_Pin;
        HAL_GPIO_Init(ENC_MOSI_GPIO_Port, &GPIO_InitStruct);
        configSPI_IT_DMA_NVIC(spiHandle);
    }
    else if (STORAGE_SPI == spiHandle->Instance)
    {
        /* SPI和GPIO时钟 */
        STORAGE_SPI_CLK_ENABLE(); //SPI时钟
        STORAGE_SCK_CLK_ENABLE();
        STORAGE_MISO_CLK_ENABLE();
        STORAGE_MOSI_CLK_ENABLE();

        /* SPI SCK */
        GPIO_InitStruct.Pin = STORAGE_SCK_Pin;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = STORAGE_SPI_PIN_AF;
        HAL_GPIO_Init(STORAGE_SCK_GPIO_Port, &GPIO_InitStruct);

        /* SPI MISO */
        GPIO_InitStruct.Pin = STORAGE_MISO_Pin;
        HAL_GPIO_Init(STORAGE_MISO_GPIO_Port, &GPIO_InitStruct);

        /* SPI MOSI */
        GPIO_InitStruct.Pin = STORAGE_MOSI_Pin;
        HAL_GPIO_Init(STORAGE_MOSI_GPIO_Port, &GPIO_InitStruct);
        configSPI_IT_DMA_NVIC(spiHandle);
    }
}
    
/**
 * @brief 配置SPI中断方式或DMA方式
 * 
 */
static void configSPI_IT_DMA_NVIC(SPI_HandleTypeDef *spiHandle)
{
    /* 配置DMA和NVIC */
    if (ENC_SPI == spiHandle->Instance)
    {
#ifdef USE_SPI_INT
        /* SPI1 interrupt Init */
        HAL_NVIC_SetPriority(ENC_SPI_IRQn, ENC_SPI_IRQ_PRIO, 0);
        HAL_NVIC_EnableIRQ(ENC_SPI_IRQn);
#endif

#ifdef USE_SPI_DMA
#endif
    }
    else if (STORAGE_SPI == spiHandle->Instance)
    {
#ifdef USE_SPI_INT
        /* SPI1 interrupt Init */
        HAL_NVIC_SetPriority(STORAGE_SPI_IRQn, STORAGE_SPI_IRQ_PRIO, 0);
        HAL_NVIC_EnableIRQ(STORAGE_SPI_IRQn);
#endif
    }
}

/**
 * @brief 由HAL_SPI_DeInit调用
 * 
 * @param spiHandle 
 */
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *spiHandle)
{
    if (spiHandle->Instance == ENC_SPI)
    {
        /* Peripheral clock disable */
        __HAL_RCC_SPI2_CLK_DISABLE();
        HAL_GPIO_DeInit(GPIOB, ENC_SCK_Pin | ENC_MISO_Pin | ENC_MOSI_Pin);

        /* SPI1 interrupt Deinit */
        HAL_NVIC_DisableIRQ(ENC_SPI_IRQn);
    }
    else if (spiHandle->Instance == STORAGE_SPI)
    {
        /* Peripheral clock disable */
        __HAL_RCC_SPI1_CLK_DISABLE();
        HAL_GPIO_DeInit(GPIOA, STORAGE_SCK_Pin | STORAGE_MISO_Pin | STORAGE_MOSI_Pin);

        /* SPI2 interrupt Deinit */
        HAL_NVIC_DisableIRQ(STORAGE_SPI_IRQn);
    }
}

/**
  * @brief This function handles SPI1 global interrupt.
  */
void ENC_SPI_IRQHandler(void)
{
    HAL_SPI_IRQHandler(&hspix[ENC_SPI_INDEX]);
}

/**
  * @brief This function handles SPI2 global interrupt.
  */
void STORAGE_SPI_IRQHandler(void)
{
    HAL_SPI_IRQHandler(&hspix[STORAGE_SPI_INDEX]);
}


// 配置SPI-DMA参考
// /* 配置DMA和NVIC */
// #ifdef USE_SPI_DMA
// {
//     /* 使能DMA时钟 */
//     DMAx_CLK_ENABLE();

//     /* SPI DMA发送配置 */
//     hdma_tx.Instance = SPIx_TX_DMA_STREAM;                  /* 例化使用的DMA数据流 */
//     hdma_tx.Init.Channel = SPIx_TX_DMA_CHANNEL;             /* DMA通道配置 */
//     hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;           /* 禁止FIFO*/
//     hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;   /* 禁止FIFO此位不起作用，用于设置阀值 */
//     hdma_tx.Init.MemBurst = DMA_MBURST_SINGLE;              /* 禁止FIFO此位不起作用，用于存储器突发 */
//     hdma_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;           /* 禁止FIFO此位不起作用，用于外设突发 */
//     hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;          /* 传输方向是从存储器到外设 */
//     hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;              /* 外设地址自增禁止 */
//     hdma_tx.Init.MemInc = DMA_MINC_ENABLE;                  /* 存储器地址自增使能 */
//     hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; /* 外设数据传输位宽选择字节，即8bit */
//     hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    /* 存储器数据传输位宽选择字节，即8bit */
//     hdma_tx.Init.Mode = DMA_NORMAL;                         /* 正常模式 */
//     hdma_tx.Init.Priority = DMA_PRIORITY_LOW;               /* 优先级低 */

//     /* 复位DMA */
//     if (HAL_DMA_DeInit(&hdma_tx) != HAL_OK)
//     {
//         Error_Handler(__FILE__, __LINE__);
//     }

//     /* 初始化DMA */
//     if (HAL_DMA_Init(&hdma_tx) != HAL_OK)
//     {
//         Error_Handler(__FILE__, __LINE__);
//     }

//     /* 关联DMA句柄到SPI */
//     __HAL_LINKDMA(_hspi, hdmatx, hdma_tx);

//     /* SPI DMA接收配置 */
//     hdma_rx.Instance = SPIx_RX_DMA_STREAM;                  /* 例化使用的DMA数据流 */
//     hdma_rx.Init.Channel = SPIx_RX_DMA_CHANNEL;             /* DMA通道配置 */
//     hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;           /* 禁止FIFO*/
//     hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;   /* 禁止FIFO此位不起作用，用于设置阀值 */
//     hdma_rx.Init.MemBurst = DMA_MBURST_SINGLE;              /* 禁止FIFO此位不起作用，用于存储器突发 */
//     hdma_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;           /* 禁止FIFO此位不起作用，用于外设突发 */
//     hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;          /* 传输方向从外设到存储器 */
//     hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;              /* 外设地址自增禁止 */
//     hdma_rx.Init.MemInc = DMA_MINC_ENABLE;                  /* 存储器地址自增使能 */
//     hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; /* 外设数据传输位宽选择字节，即8bit */
//     hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    /* 存储器数据传输位宽选择字节，即8bit */
//     hdma_rx.Init.Mode = DMA_NORMAL;                         /* 正常模式 */
//     hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;              /* 优先级低 */

//     /* 复位DMA */
//     if (HAL_DMA_DeInit(&hdma_rx) != HAL_OK)
//     {
//         Error_Handler(__FILE__, __LINE__);
//     }

//     /* 初始化DMA */
//     if (HAL_DMA_Init(&hdma_rx) != HAL_OK)
//     {
//         Error_Handler(__FILE__, __LINE__);
//     }

//     /* 关联DMA句柄到SPI */
//     __HAL_LINKDMA(_hspi, hdmarx, hdma_rx);

//     /* 配置DMA发送中断 */
//     HAL_NVIC_SetPriority(SPIx_DMA_TX_IRQn, 1, 0);
//     HAL_NVIC_EnableIRQ(SPIx_DMA_TX_IRQn);

//     /* 配置DMA接收中断 */
//     HAL_NVIC_SetPriority(SPIx_DMA_RX_IRQn, 1, 0);
//     HAL_NVIC_EnableIRQ(SPIx_DMA_RX_IRQn);

//     /* 配置SPI中断 */
//     HAL_NVIC_SetPriority(SPIx_IRQn, 1, 0);
//     HAL_NVIC_EnableIRQ(SPIx_IRQn);
// }
// #endif
